/*
 * @Author: Wangjun
 * @Date: 2021-08-20 11:00:46
 * @LastEditTime: 2022-05-20 14:33:53
 * @LastEditors: Wangjun
 * @Description:struct 和 xlsx 转换
 * @FilePath: \golib\structdetail\struct_detail.go
 * hnxr
 */
package models

import (
	"errors"
	"reflect"
)

type Xlsx struct {
}

// func (m *Xlsx) Save(filename string) (err error) {
// 	forms := make([]*BasicFanModelFormula, 1)
// 	f := new(BasicFanModelFormula)
// 	forms[0] = f

// 	return
// }

// 列信息
type Column struct {
	reflect.StructField
	Title     string
	FullName  string
	FullIndex []int //全路径
}

//struct 信息
type StructDetail struct {
	Name    string
	Columns []*Column
	err     error //错误消息

	tagKey string //要读取tag key
}

/**
 * @description: 新的映射关系
 * @param {interface{}} arrayObject	struct 数组
 * @param {string} tagKey  需要识别的tag字段
 * @return {*}
 */
func NewStructMap(arrayObject interface{}, tagKey string) (sm *StructDetail) {
	sm = new(StructDetail)
	sm.tagKey = tagKey
	sm.init(arrayObject)
	return
}

/**
 * @description: 初始化数据
 * @param {interface{}} arrayObject
 * @return {*}
 */
func (m *StructDetail) init(arrayObject interface{}) {
	//关联key的索引
	t := reflect.TypeOf(arrayObject)
	if !(t.Kind() == reflect.Slice || t.Kind() == reflect.Array) {
		m.err = errors.New("参数错误，参数必须是结构体切片或者数组")
		return
	}
	t = t.Elem()
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	if t.Kind() != reflect.Struct {
		m.err = errors.New("数组的内容不是结构体")
		return
	}
	m.initColumn("", nil, t)
}

/**
 * @description: 初始化列
 * @param {string} prefix 前缀 上一路径名
 * @param {[]int} paths 上一路径ID
 * @param {reflect.Type} t 类型
 * @return {*}
 */
func (m *StructDetail) initColumn(prefix string, paths []int, t reflect.Type) {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	for i := 0; i < t.NumField(); i++ {
		newPaths := make([]int, len(paths))
		copy(newPaths, paths)
		newPaths = append(newPaths, i)
		fieldType := t.Field(i)

		typ := fieldType.Type

		if typ.Kind() == reflect.Ptr {
			typ = typ.Elem()
		}

		title := ""
		if m.tagKey != "" {
			title = fieldType.Tag.Get(m.tagKey)
			if title == "-" {
				continue
			}
		}

		fullName := prefix + fieldType.Name
		if fieldType.Anonymous {
			if typ.Kind() == reflect.Struct {
				m.initColumn(prefix, newPaths, typ)
				continue
			}
		} else {
			if typ.Kind() == reflect.Struct {
				if fieldType.Name == "" {
					continue
				}
				if fieldType.Name[0] >= 'A' && fieldType.Name[0] <= 'Z' {
					m.initColumn(fullName+".", newPaths, typ)
				}
			} else {
				if !(fieldType.Name[0] >= 'A' && fieldType.Name[0] <= 'Z') {
					continue
				}
			}
		}

		col := new(Column)
		col.StructField = fieldType
		col.FullIndex = newPaths

		if title == "" {
			title = fullName
		}
		col.Title = title
		m.Columns = append(m.Columns, col)
	}
}
